﻿using System;
using System.Drawing.Win32;
using HoldemGame;
using Layers;
using System.Collections.Generic;

/*
 qt_scrollarea_viewport == list view -- used in CHAT, TABLE LIST
 MainWindow

 */
namespace HoldemHook
{

    enum FTState
    {
        WaitHandStart,
        CollectPlayers,
        SitDown,
        Playing
    };

    public class FTChatParser
    {

        ITextOutEventSource _table;

        IGame _target;

        string prefix = "Dealer: ";
        string postbb = " posts the big blind of ";
        string postsb = " posts the small blind of ";
        string handno = "Hand #";
        string timeleft = " seconds left to act";
        string posts = " posts ";
        string mycards = "You have been dealt [";
        string checks = " checks";
        string raisesto = " raises to ";
        string calls = " calls ";
        string folds = " folds";
        string turn = "The turn is [";
        string river = "The river is [";
        string flop = "The flop is [";
        string bets = " bets ";
        string adds = " adds ";
        string shows = " shows ";
        string winsmain = " wins the main pot (";
        string wins = " wins the pot (";
        string winswith = ") with ";
        string sitout = " is sitting out";
        string reconnect = " has reconnected";
        string ties = " ties for the pot (";
        string disconnect = " has been disconnected";
        string mucks = " mucks";
        string standup = " stands up";
        string secleft = " seconds left to act";
        string has = " has ";
        string rcp = ")";
        string rsp = "]";
        string uncalledbet = "Uncalled bet of ";
        string returnedto = " returned to ";
        string sitdown = " sits down";

        int position = 0;
        long handId = 0;
        int step = -1;

        FTState state;

        string MyName = null;
        long lastHandId = -1;

        List<String> players = new List<String>();

        List<TextOutEventArgs> events = new List<TextOutEventArgs>();
        DateTime LastTextOutEventTime = DateTime.MinValue;

        CardSet _boardCards = new CardSet();
        string hasreturned = " has returned";

        public enum Post : uint
        {
            Money = 0,
            SmallBlind = 1,
            BigBlind = 2
        }

        public FTChatParser(ITextOutEventSource table, IGame target)
        {
            //_chat = table.Chat;
            _target = target;
            _table = table;
            _table.TextOutEvent += new EventHandler<TextOutEventArgs>(OnNewMessage);
            state = FTState.WaitHandStart;
        }

        void OnNewMessage(object sender, TextOutEventArgs e)
        {
            if (e.Message.StartsWith("Dealer:"))
            {
                
                FilterMessage(e);
            }
        }

        void FilterMessage(TextOutEventArgs e)
        {
            if(e.InTime>LastTextOutEventTime)
            {
                MyLogger.WriteLine("[{0}:{1}:{2}.{3}]{4}", e.InTime.Hour, e.InTime.Minute, e.InTime.Second, e.InTime.Millisecond, e.Message);
                LastTextOutEventTime = e.InTime;
                Parse(e.Message);
            }

        }

        double ParseDouble(string msg)
        {
            int pAllIn = msg.IndexOf(", and is");
            if (pAllIn >= 0)
                msg = msg.Substring(0, pAllIn);
            string msg2 = msg.Trim('$', ' ', ',');
            string msg3 = msg2.Replace(",", "");
            if (msg3 != msg)
                MyLogger.WriteLine("PARSE: [{0}]->[{1}]", msg, msg3);
            try
            {

                return double.Parse(msg3);
            }
            catch (Exception e)
            {
                MyLogger.WriteLine("ERR: Failed to Parse Double [{0}]", msg3);
                return double.NaN;
            }
        }

        void Parse(string msg)
        {
            if (!msg.StartsWith(prefix))
                throw new InvalidOperationException(string.Format("Message {0} doesn't start with {1} prefix", msg, prefix));
            try
            {
                msg = msg.Substring(prefix.Length);

                int i, j;

                i = msg.IndexOf(handno);
                if (i >= 0)
                {
                    HandStart(long.Parse(msg.Substring(i + handno.Length)));
                    return;
                }

                i = msg.IndexOf(postbb);
                if (i >= 0)
                {
                    Blind(msg.Substring(0, i), ParseDouble(msg.Substring(i + postbb.Length)), Post.BigBlind);
                    return;
                }

                i = msg.IndexOf(postsb);
                if (i >= 0)
                {
                    Blind(msg.Substring(0, i), ParseDouble(msg.Substring(i + postsb.Length)), Post.SmallBlind);
                    return;
                }

                i = msg.IndexOf(timeleft);
                if (i >= 0)
                {
                    //bobeobi has 15 seconds left to act
                    if (msg[0] >= '0' && msg[0] <= '9')
                    {
                        TimeLeft(null, ParseDouble(msg.Substring(0, i)));
                        return;
                    }
                    else
                    {
                        j = msg.IndexOf(has);
                        int k = msg.IndexOf(secleft);

                        if (j >= 0)
                        {
                            if (k >= 0)
                            {
                                TimeLeft(msg.Substring(0, j), ParseDouble(msg.Substring(j + has.Length, k - j - has.Length)));
                                return;
                            }
                        }
                        else
                        {
                            TimeLeft(null, ParseDouble(msg.Substring(0, i)));
                            return;
                        }
                    }
                }

                i = msg.IndexOf(posts);
                if (i >= 0)
                {
                    Blind(msg.Substring(0, i), ParseDouble(msg.Substring(i + posts.Length)), Post.Money);
                    return;
                }

                i = msg.IndexOf(mycards);
                if (i >= 0)
                {
                    j = msg.IndexOf(rsp);
                    if (j >= 0)
                    {
                        MyCards(msg.Substring(i, j - i));
                        return;
                    }
                }

                i = msg.IndexOf(checks);
                if (i >= 0)
                {
                    Check(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(raisesto);
                if (i >= 0)
                {
                    RaiseTo(msg.Substring(0, i), ParseDouble(msg.Substring(i + raisesto.Length)));
                    return;
                }

                i = msg.IndexOf(calls);
                if (i >= 0)
                {
                    Call(msg.Substring(0, i), ParseDouble(msg.Substring(i + calls.Length)));
                    return;
                }

                i = msg.IndexOf(bets);
                if (i >= 0)
                {
                    Bet(msg.Substring(0, i), ParseDouble(msg.Substring(i + bets.Length)));
                    return;
                }

                i = msg.IndexOf(adds);
                if (i >= 0)
                {
                    BetAdd(msg.Substring(0, i), ParseDouble(msg.Substring(i + adds.Length)));
                    return;
                }

                i = msg.IndexOf(uncalledbet);
                if (i >= 0)
                {
                    j = msg.IndexOf(returnedto);
                    if (j >= i)
                    {
                        BetReturn(msg.Substring(j + returnedto.Length),
                            ParseDouble(msg.Substring(i + uncalledbet.Length, j - i - uncalledbet.Length)));
                        return;
                    }
                }
                i = msg.IndexOf(folds);
                if (i >= 0)
                {
                    Fold(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(flop);
                if (i >= 0)
                {
                    j = msg.IndexOf(rsp);
                    if (j >= 0)
                    {
                        Flop(msg.Substring(i + flop.Length, j - i - flop.Length));
                        return;
                    }
                }

                i = msg.IndexOf(turn);
                if (i >= 0)
                {
                    j = msg.IndexOf(rsp);
                    if (j >= 0)
                    {
                        Turn(msg.Substring(i + turn.Length, j - i - turn.Length));
                        return;
                    }
                }

                i = msg.IndexOf(river);
                if (i >= 0)
                {
                    j = msg.IndexOf(rsp);
                    if (j >= 0)
                    {
                        River(msg.Substring(i + river.Length, j - i - river.Length));
                        return;
                    }
                }

                i = msg.IndexOf(shows);
                if (i >= 0)
                {
                    j = msg.IndexOf(rsp);
                    if (j >= 0)
                    {
                        Shows(msg.Substring(0, i), msg.Substring(i + shows.Length, j - i - shows.Length));
                        return;
                    }
                    else
                    {
                        Shows(msg.Substring(0, i), msg.Substring(i + shows.Length));
                        return;
                    }
                }

                i = msg.IndexOf(wins);
                if (i >= 0)
                {
                    j = msg.IndexOf(winswith);

                    string comb = null;
                    if (j >= 0)
                        comb = msg.Substring(j + winswith.Length);
                    int k = msg.IndexOf(rcp);
                    if (k >= i + wins.Length)
                    {
                        Wins(msg.Substring(0, i),
                            ParseDouble(msg.Substring(i + wins.Length, k - i - wins.Length)), comb);
                        return;
                    }
                }

                i = msg.IndexOf(winsmain);
                if (i >= 0)
                {
                    j = msg.IndexOf(winswith);
                    string comb = null;
                    if (j >= 0)
                        comb = msg.Substring(j + winswith.Length);
                    int k = msg.IndexOf(rcp);
                    if (k >= i + winsmain.Length)
                    {
                        Wins(msg.Substring(0, i),
                            ParseDouble(msg.Substring(i + winsmain.Length, k - i - winsmain.Length)), comb);
                        return;
                    }
                }

                i = msg.IndexOf(ties);
                if (i >= 0)
                {
                    j = msg.IndexOf(winswith);
                    string comb = null;
                    if (j >= 0)
                        comb = msg.Substring(j + winswith.Length);
                    int k = msg.IndexOf(rcp);
                    if (k >= i + ties.Length)
                    {
                        Ties(msg.Substring(0, i),
                            ParseDouble(msg.Substring(i + ties.Length, k - i - ties.Length)), comb);
                        return;
                    }
                }


                i = msg.IndexOf(sitout);
                if (i >= 0)
                {
                    SitOut(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(sitdown);
                if (i >= 0)
                {
                    SitDown(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(standup);
                if (i >= 0)
                {
                    StandUp(msg.Substring(0, i));
                    return;
                }


                i = msg.IndexOf(reconnect);
                if (i >= 0)
                {
                    Reconnect(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(disconnect);
                if (i >= 0)
                {
                    Disconnect(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(hasreturned);
                if (i >= 0)
                {
                    Returned(msg.Substring(0, i));
                    return;
                }

                i = msg.IndexOf(mucks);
                if (i >= 0)
                {
                    Muck(msg.Substring(0, i));
                    return;
                }


                NotParsed(msg, null);
            }
            catch (Exception e)
            {
                NotParsed(msg, e);
            }
        }

        void NotParsed(string unparsed, Exception e)
        {
            Layers.MyLogger.WriteLine("NotParsed({0}). Error {1}", unparsed, e);
        }

        void SitOut(string player)
        {
            Layers.MyLogger.WriteLine("SitOut({0})", player);
        }

        void Returned(String player)
        {
            Layers.MyLogger.WriteLine("Returned({0})", player);
        }

        void SitDown(string player)
        {
             Layers.MyLogger.WriteLine("SitDown({0})", player);
             if (state == FTState.Playing)
             {
                 players.Add(player);
                 DumpPlayers();
             }
        }

        void StandUp(string player)
        {
            
            Layers.MyLogger.WriteLine("StandUp({0})", player);
            if (state == FTState.Playing)
            {
                players.Remove(player);
                DumpPlayers();
            }
        }

        void Reconnect(string player)
        {
            Layers.MyLogger.WriteLine("Reconnect({0})", player);
        }

        void Disconnect(string player)
        {
            Layers.MyLogger.WriteLine("Disconnect({0})", player);
        }

        void Muck(string player)
        {
            Layers.MyLogger.WriteLine("Muck({0})", player);
            HasPlayer(player);
        }

        void Wins(string player, double pot, string comb)
        {
            Layers.MyLogger.WriteLine("Wins({0},{1},{2})", player, pot, comb);
            HasPlayer(player);
        }

        void Ties(string player, double pot, string comb)
        {
            Layers.MyLogger.WriteLine("Wins({0},{1},{2})", player, pot, comb);
            HasPlayer(player);
        }

        void Shows(string player, string comb)
        {
            Layers.MyLogger.WriteLine("Shows({0},{1})", player, comb);
            HasPlayer(player);
        }

        void River(string card)
        {
            CardSet river = CardSet.ParseAll(card, 1);

            Layers.MyLogger.WriteLine("River({0})", river);

            _target.Server.PostRiver(river);
        }

        void Turn(string card)
        {
            CardSet turn = CardSet.ParseAll(card, 1);
            Layers.MyLogger.WriteLine("Turn({0})", turn);
            _target.Server.PostTurn(turn);
        }

        void Flop(string cards)
        {
            CardSet flop = CardSet.ParseAll(cards, 3);
            Layers.MyLogger.WriteLine("Flop({0}) ", flop);
            if (null != _target)
                _target.Server.PostFlop(flop);
        }

        void Fold(string player)
        {
            Layers.MyLogger.WriteLine("Fold({0})", player);
            HasPlayer(player);
        }

        void Bet(string player, double amount)
        {
            Layers.MyLogger.WriteLine("Bet({0},{1})", player, amount);
            HasPlayer(player);
        }

        void BetAdd(string player, double amount)
        {
            Layers.MyLogger.WriteLine("BetAdd({0},{1})", player, amount);
            HasPlayer(player);
        }

        void BetReturn(string player, double amount)
        {
            Layers.MyLogger.WriteLine("BetReturn({0},{1})", player, amount);
            HasPlayer(player);
        }

        void Call(string player, double amount)
        {
            Layers.MyLogger.WriteLine("Call({0},{1})", player, amount);
            HasPlayer(player);
        }

        void RaiseTo(string player, double toAmount)
        {
            Layers.MyLogger.WriteLine("RaiseTo({0},{1})", player, toAmount);
            HasPlayer(player);
        }

        void Check(string player)
        {
            Layers.MyLogger.WriteLine("Check({0})", player);
            HasPlayer(player);
        }

        GamePlayer PlayerFromName(string MyName)
        {
            if (null != _target)
            {
                GamePlayer p = _target.State.Players.FromName(MyName);
                return p;
            }
            return null;
        }

        void MyCards(string cards)
        {
            GamePlayer p = null;
            if (null != _target)
            {
                p = PlayerFromName(MyName);
                if (null == p)
                    throw new InvalidOperationException(string.Format("No {0} player at the table", MyName));
                //_target.Server.SetCurrent(p);
                _target.Server.PocketCards(p, CardSet.ParseAll(cards, 2));
            }

            Layers.MyLogger.WriteLine("SetCurrent({1}), MyCards({0})", cards, p);
            HasPlayer(MyName);

        }

        void Blind(string player, double blind, Post kind)
        {
            Layers.MyLogger.WriteLine("Blind({0},{1},{2})", player, blind, kind);
            HasPlayer(player);
        }

        void TimeLeft(string player, double time)
        {

            Layers.MyLogger.WriteLine("TimeLeft({0},{1})", player, time);
            HasPlayer(player);
        }

        void ToState(FTState newState)
        {
            Layers.MyLogger.WriteLine("STATE:{0}", newState);
            state=newState;
        }
        void HandStart(long id)
        {
            Layers.MyLogger.WriteLine("HandStart({0})", id);
            if (state == FTState.WaitHandStart)
                ToState(FTState.CollectPlayers);
            else
                if (state == FTState.CollectPlayers)
                {
                    ToState(FTState.Playing);
                    SetPlayers();
                }

            if (state != FTState.Playing)
                return;

            position = 0;
            position = 0;
            handId = id;
            //if (null != _table)
            //    _table.Mosaic.Tiles.Clear();

            if (null != _target)
            {
                _target.Server.NewGame();
                step++; // now at step "0"
            }

        }

        void HasPlayer(string player)
        {
            if(state==FTState.CollectPlayers)
            {
                if (players.IndexOf(player) < 0)
                {
                    players.Add(player);
                    DumpPlayers(); 
                }
            }
        }

        void DumpPlayers()
        {

            for (int i = 0; i < players.Count; i++)
            {
                MyLogger.WriteLine("[{0}]={1}", i, players[i]);
            }
 
        }

        void SetPlayers()
        {
            IGameState game = _target.State;
            game.Table.Seats.Resize(players.Count);
            for (int i = 0; i < players.Count; i++)
            {
                GamePlayer p = new GamePlayer(game as Game,players[i]);
                game.Table.Seats[i].SitDown(p);
            }
        }

    }
}